package com.avic.modules.backup4MySQL.rest;

import com.avic.exception.BadRequestException;
import com.avic.modules.backup4MySQL.MySQLBackup;
import com.avic.modules.backup4MySQL.vo.BackupVo;
import com.avic.modules.log.domain.vo.LogEnumeration;
import com.avic.modules.log.domain.vo.LogVo;
import com.avic.modules.log.service.LogsService;
import com.avic.modules.quartz.domain.QuartzJob;
import com.avic.modules.quartz.service.QuartzJobService;
import com.avic.modules.quartz.utils.QuartzManage;
import com.avic.modules.storage.utils.ResponseUtils;
import com.avic.utils.DateUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.io.File;
import java.io.IOException;
import java.net.URLDecoder;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.sql.SQLException;
import java.text.ParseException;
import java.util.List;

@RestController
@Api(tags = "系统：数据库备份")
@RequestMapping("/api/backup")
@Slf4j
public class BackupController {

    private final QuartzJobService quartzJobService;
    private final MySQLBackup mySQLBackup;
    private final LogsService logsService;
    private final QuartzManage quartzManage;

    public BackupController(QuartzJobService quartzJobService, MySQLBackup mySQLBackup, LogsService logsService, QuartzManage quartzManage) {
        this.quartzJobService = quartzJobService;
        this.mySQLBackup = mySQLBackup;
        this.logsService = logsService;
        this.quartzManage = quartzManage;
    }

    public static void main(String[] args) throws IOException {
        String sqlBackupDir = MySQLBackup.SQL_EXTERNAL_DIR.concat(MySQLBackup.SQL_TMP_DIR);
        File sqlDumpFile = new File(sqlBackupDir);
    }

    @ApiOperation("查询所有备份 SQL 文件")
    @RequestMapping("/list")
//    @PreAuthorize("@el.check('admin','backup:list')")
    public ResponseEntity<Object> list() throws IOException {
        return new ResponseEntity<>(MySQLBackup.getSqlPathMap(), HttpStatus.OK);
    }

    @ApiOperation("设置数据库备份定时任务")
    @RequestMapping("/doTask")
//    @PreAuthorize("@el.check('admin','backup:fixedtimetask')")
    public ResponseEntity<Object> doFixedTimeBackupTask(@Validated @RequestBody BackupVo backupVo) {
        QuartzJob backupJob = new QuartzJob();
        List<QuartzJob> quartzJobList = quartzJobService.checkBackupJob();
        if (quartzJobList.size() == 0) {
            backupJob.setBeanName("mySQLBackupTask");
            backupJob.setMethodName("runMySQLDump");
            backupJob.setRemark("daily backup job,don't delete");
            backupJob.setJobName("doFixedTimeBackupTask 数据库定时备份");
            backupJob.setIsPause(false);
            /**
             * 默认每天 18 点备份一次
             */
            backupJob.setCronExpression("0 0 18 * * ?");
            if (quartzJobService.save(backupJob)) {
                quartzJobService.execution(quartzJobService
                        .getOne(new LambdaQueryWrapper<QuartzJob>().eq(QuartzJob::getId, quartzJobService.checkBackupJob().get(0).getId())));
                return new ResponseEntity<>(HttpStatus.OK);
            } else {
                throw new BadRequestException(HttpStatus.EXPECTATION_FAILED, "创建备份任务失败");
            }
        } else {
            QuartzJob quartzJob = quartzJobList.get(0);
            quartzJob.setCronExpression(backupVo.getCronExpression());
            /**
             * 由于 quartz job 异常会设置为 pause 状态，所以此时需要强制置为开启
             */
            quartzJob.setIsPause(false);
            if (quartzJobService.updateById(quartzJob)) {
                // 更新成功后，激活
                quartzManage.updateJobCron(quartzJob);
                log.info("update quartz job,{}",quartzJob);
                return new ResponseEntity<>(HttpStatus.OK);
            } else {
                throw new BadRequestException(HttpStatus.EXPECTATION_FAILED, "修改备份任务失败");
            }
        }
    }

    @ApiOperation("查询备份任务")
    @RequestMapping("/checkBackupJob")
//    @PreAuthorize("@el.check('admin','backup:checkbackup')")
    public ResponseEntity<Object> checkBackup() throws ParseException {
        List<QuartzJob> quartzJobList = quartzJobService.checkBackupJob();
        if (quartzJobList.size() == 0){
            return new ResponseEntity<>(null, HttpStatus.OK);
        }else{
            BackupVo backupVo = new BackupVo();
            backupVo.setBackupTime(BackupVo.getTimeStrFromCronExpression(quartzJobList.get(0).getCronExpression()));
            return new ResponseEntity<>(backupVo, HttpStatus.OK);
        }

    }

    @ApiOperation("手动执行数据库备份")
    @RequestMapping("/dump")
//    @PreAuthorize("@el.check('admin','backup:manual')")
    public ResponseEntity<Object> dumpMySQL() throws SQLException, IOException, ClassNotFoundException {
        mySQLBackup.exportSQL();
        if (mySQLBackup.getSqlPath() == null) {
            logBackup(" 执行失败 ");
            return new ResponseEntity<>(mySQLBackup, HttpStatus.EXPECTATION_FAILED);
        } else {
            logBackup(" 执行成功 ");
            return new ResponseEntity<>(mySQLBackup, HttpStatus.OK);
        }
    }


    private void logBackup(String s) {
        LogVo logVo = new LogVo();
        String behavior = "[ MYSQL 手工备份 ]" + s;
        logVo.setAction(LogEnumeration.Backup.getMessage());
        logVo.setBehavior(behavior);
        logsService.save(logVo);
    }


    /**
     *
     * @param pathName
     * @return
     * @throws IOException
     */
    @ApiOperation("下载备份数据库文件，支持多选")
    @RequestMapping("/download")
//    @PreAuthorize("@el.check('admin','backup:download')")
    public ResponseEntity<byte[]> downloadSQL(@RequestParam String pathName) throws IOException {
        LogVo logVo = new LogVo();
        String name = "[下载]了数据备份";
        logVo.setBehavior(name);
        logVo.setAction(LogEnumeration.Backup.getMessage());
        logsService.save(logVo);
        String fileName = DateUtils.dateTimeNow() + MySQLBackup.SQL_EXTENSION;
        pathName = URLDecoder.decode(pathName,"utf-8");
//        pathName = MySQLBackup.SQL_EXTERNAL_DIR + MySQLBackup.SQL_TMP_DIR + pathName;
        if (Files.exists(Paths.get(pathName)) &&  pathName.endsWith(MySQLBackup.SQL_EXTENSION)) {
            return ResponseUtils.getResponseEntity(fileName, pathName, false);
        }
        return new ResponseEntity<>(HttpStatus.NOT_FOUND);
    }

}
